package com.heima.search.service.impl;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.search.dtos.UserSearchDto;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import com.heima.utils.threadlocal.AppThreadLocalUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Description:
 * @Version: V1.0
 */
@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {

    @Autowired
    RestHighLevelClient client;

    @Value("${elasticsearch.index_data}")
    private String index;


    @Autowired
    ApUserSearchService apUserSearchService;

    /**
     * 搜索
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto dto) {
        //1 参数校验
        if (dto == null || StringUtils.isBlank(dto.getSearchWords())) {
            return ResponseResult.okResult();
        }
        // 最小时间
        if (dto.getMinBehotTime() == null) {
            dto.setMinBehotTime(new Date());
        }
        // size
        if (dto.getPageSize() <= 0 || dto.getPageSize() > 50) {
            dto.setPageSize(10);
        }

        // ***** 异步保存
        ApUser user = AppThreadLocalUtils.getUser();
        if (user != null && user.getId() != 0) {
            log.info("******开始异步保存关键词*******");
            apUserSearchService.insert(dto.getSearchWords(), user.getId());
        }



        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //2 构建查询条件 bool
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        //2.1 添加关键词查询
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", dto.getSearchWords());
        queryBuilder.must(matchQueryBuilder);

        //2.2 添加过滤条件 minDate 当前页下的最后一条记录的发布时间 --> 按照发布时间倒序
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders
                .rangeQuery("publishTime").lt(dto.getMinBehotTime());
        queryBuilder.filter(rangeQueryBuilder);
        //**** 条件过滤

        //2.3 排序 发布时间 降序
        searchSourceBuilder.sort("publishTime", SortOrder.DESC);

        //2.4 分页 size， from=0
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(dto.getPageSize());

        //2.5 高亮 三要素
        HighlightBuilder hbuilder = new HighlightBuilder();
        hbuilder.field("title");
        hbuilder.preTags("<font style='color: red; font-size: inherit;'>");
        hbuilder.postTags("</font>");
        searchSourceBuilder.highlighter(hbuilder);

        //3 执行查询
        SearchRequest request = new SearchRequest(index);
        searchSourceBuilder.query(queryBuilder);
        request.source(searchSourceBuilder);

        List<Map> result = new ArrayList<>();

        try {
            SearchResponse searchResponse = client.search(request, RequestOptions.DEFAULT);
            //4 解析结果
            SearchHits hits = searchResponse.getHits();
            SearchHit[] searchHits = hits.getHits();
            for (SearchHit searchHit : searchHits) {

                // 得到结果
                Map<String, Object> map = searchHit.getSourceAsMap();

                // 得到高亮
                HighlightField highlightField = searchHit.getHighlightFields().get("title");
                if (highlightField != null && highlightField.getFragments().length > 0) {
                    Text[] fragments = highlightField.getFragments();
                    String title = StringUtils.join(fragments);
                    map.put("h_title", title);
                }else {
                    map.put("h_title", map.get("title"));
                }

                result.add(map);
            }

            return ResponseResult.okResult(result);
        } catch (IOException e) {
//            e.printStackTrace();
            log.error("search is error:{}", e);
        }

        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
    }

}
